package com.slx.sthq.config;

import com.slx.sthq.common.utils.file.MultipartFileResource;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Component
public class SeaweedFSConfig {

    // 从配置文件中读取 SeaweedFS Filer 的 URL
    @Value("${seaweedfs.filer.url}")
    private String seaweedfsFilerUrl;

    // 依赖注入 RestTemplate，用于发送 HTTP 请求
    @Autowired
    private RestTemplate restTemplate;

    /**
     * 上传文件到指定路径
     *
     * @param file     上传的文件
     * @param filePath 文件存储路径（例如：/images/）
     * @return 文件的完整路径
     * @throws IOException 如果上传失败
     */
    public String uploadFile(MultipartFile file, String filePath) throws IOException {
        // 验证文件路径是否合法
        if (filePath == null || filePath.isEmpty() || filePath.contains("..")) {
            throw new IllegalArgumentException("Invalid file path");
        }
        // 构建文件存储路径，包含日期
        // 构建文件存储路径，包含日期
        StringBuilder pathBuilder = new StringBuilder();
        pathBuilder.append("/")
                .append(filePath)
                .append("/")
                .append(DateFormatUtils.format(new Date(), "yyyyMMdd"))
                .append("/");
        // 构建完整的上传 URL
        String url = seaweedfsFilerUrl + pathBuilder;

        // 设置请求头，指定内容类型为 multipart/form-data
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);

        // 构建请求体，包含文件
        MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
        body.add("file", new MultipartFileResource(file));

        // 创建请求实体，包含请求头和请求体
        HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);

        // 发送 POST 请求上传文件
        ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
        if (response.getStatusCode().is2xxSuccessful()) {
            // 如果上传成功，返回文件的完整路径
            return pathBuilder + file.getOriginalFilename();
        } else {
            // 如果上传失败，抛出 IOException 并包含错误信息
            throw new IOException("Failed to upload file: " + response.getBody());
        }
    }

    /**
     * 下载文件
     *
     * @param filePath 文件的完整路径
     * @return 文件的字节数组
     * @throws IOException 如果下载失败
     */
    public byte[] downloadFile(String filePath) throws IOException {
        // 验证文件路径是否合法
        if (filePath == null || filePath.isEmpty() || filePath.contains("..")) {
            throw new IllegalArgumentException("Invalid file path");
        }
        // 构建完整的下载 URL
        String url = seaweedfsFilerUrl + filePath;

        // 发送 GET 请求下载文件
        ResponseEntity<byte[]> response = restTemplate.getForEntity(url, byte[].class);
        if (response.getStatusCode().is2xxSuccessful()) {
            // 如果下载成功，返回文件的字节数组
            return response.getBody();
        } else {
            // 如果下载失败，抛出 IOException 并包含错误状态码
            throw new IOException("Failed to download file: " + response.getStatusCode());
        }
    }

    /**
     * 删除文件
     *
     * @param filePath 文件的完整路径
     * @throws IOException 如果删除失败
     */
    public void deleteFile(String filePath) throws IOException {
        // 构建完整的删除 URL
        String url = seaweedfsFilerUrl + filePath;

        // 发送 DELETE 请求删除文件
        ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.DELETE, null, String.class);
        if (!response.getStatusCode().is2xxSuccessful()) {
            // 如果删除失败，抛出 IOException 并包含错误信息
            throw new IOException("Failed to delete file: " + response.getBody());
        }
    }

    /**
     * 将文件内容写入响应
     *
     * @param response    HttpServletResponse
     * @param fileContent 文件内容
     * @throws IOException 如果写入失败
     */
    public void writeToResponse(HttpServletResponse response, byte[] fileContent) throws IOException {
        // 使用 try-with-resources 语句确保 OutputStream 在使用后自动关闭
        try (OutputStream outputStream = response.getOutputStream()) {
            // 将文件内容写入响应输出流
            outputStream.write(fileContent);
            // 刷新输出流，确保所有数据都被写入
            outputStream.flush();
        }
    }

    /**
     * 设置响应头
     *
     * @param response HttpServletResponse
     * @param fileName 文件名
     * @throws UnsupportedEncodingException 如果文件名编码失败
     */
    public void setResponseHeaders(HttpServletResponse response, String fileName) throws UnsupportedEncodingException {
        // 设置 Content-Type 为 application/octet-stream，表示二进制数据
        response.setContentType("application/octet-stream");

        // 对文件名进行 URL 编码，替换空格为 %20
        String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.toString())
                .replaceAll("\\+", "%20");

        // 设置 Content-Disposition，使浏览器以附件形式下载文件
        String disposition = "attachment; filename=\"" + encodedFileName + "\"; " +
                "filename*=UTF-8''" + encodedFileName;
        response.setHeader("Content-Disposition", disposition);
    }

    /**
     * 获取路径的最后一段
     *
     * @param path 路径字符串
     * @return 路径的最后一段，如果没有 /，返回整个字符串
     */
    public String getLastSegment(String path) {
        if (path == null || path.isEmpty()) {
            return "";
        }
        // 使用正则表达式匹配路径的最后一段
        Pattern pattern = Pattern.compile("/([^/]+)$");
        Matcher matcher = pattern.matcher(path);
        if (matcher.find()) {
            // 如果匹配成功，返回最后一段
            return matcher.group(1);
        }
        // 如果没有 /，返回整个字符串
        return path;
    }
}


